package com.gitee.baqkft.code.ui.dlg;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import org.mybatis.generator.config.JDBCConnectionConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gitee.baqkft.code.core.beans.BeanFileHandler;
import com.gitee.baqkft.code.core.db.SQLHandler;
import com.gitee.baqkft.code.core.docs.DBDocHandler;
import com.gitee.baqkft.code.db.DBTable;
import com.gitee.baqkft.code.db.DBUtils;
import com.gitee.baqkft.code.model.DataTableListModel;
import com.gitee.baqkft.code.model.DataTableModel;
import com.gitee.baqkft.code.ui.component.ConnectionSettingPanel;
import com.gitee.baqkft.code.ui.component.ListAndDetailPanel;
import com.gitee.baqkft.code.ui.layout.GBC;

/**
 * 程序主界面
 * @author chenmingcai
 * @date 2018年5月19日 上午10:20:34
 *
 */

public class MainUI extends JFrame implements ConnectionSettingPanel.ConnectionAction, ListSelectionListener
{

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	private static final Logger logger = LoggerFactory.getLogger(MainUI.class);

	/**
	 * 数据表
	 */
	private List<DBTable> dbTables = new ArrayList<>();

	/**
	 * 主要内容
	 */
	private ListAndDetailPanel content;

	/**
	 * 选择表复选框
	 */
	private JCheckBox sltTable;

	/**
	 * 弹出菜单
	 */
	private JPopupMenu popupMenu;

	/**
	 * 数据连接配置
	 */
	private JDBCConnectionConfiguration connectionConfiguration;

	/**
	 * Mybatis Plus数据源
	 */
	private DataSourceConfig dataSourceConfig;

	public MainUI()
	{
		initUI();
	}

	/**
	 * 初始化界面
	 */
	private void initUI()
	{
		//设置尺寸
		Toolkit kit = Toolkit.getDefaultToolkit();
		Dimension screenSize = kit.getScreenSize();
		int width = screenSize.width / 2;
		int height = screenSize.height / 2;
		setSize(width, height);
		setLocationByPlatform(true);

		//设置菜单栏
		initMenuBar();

		setLayout(new GridBagLayout());

		ConnectionSettingPanel setting = new ConnectionSettingPanel();
		GBC gbc = new GBC(0, 0).setWeight(1, 0).setFill(GBC.HORIZONTAL).setInsets(10);
		add(setting, gbc);
		setting.setConnectionAction(this);

		content = new ListAndDetailPanel();
		gbc = new GBC(0, 10).setWeight(1, 1).setFill(GBC.BOTH).setInsets(10);
		add(content, gbc);

		//事件设置
		content.getTableList().addListSelectionListener(this);
		popupMenu = createPopupMenu();

		//右键菜单
		content.getTableList().addMouseListener(new MouseAdapter()
		{
			@Override
			public void mouseClicked(MouseEvent e)
			{
				JList<String> list = content.getTableList();
				if(e.getButton() == MouseEvent.BUTTON3 && list.getSelectedIndex() >= 0)
				{
					popupMenu.show(list, e.getX(), e.getY());
				}
				super.mouseClicked(e);
			}

		});

		JPanel optionsRow = createOptions();
		gbc = new GBC(0, 20).setWeight(0, 0).setInsets(0, 0, 5, 0);
		add(optionsRow, gbc);
	}

	/**
	 * 初始化菜单栏
	 */
	private void initMenuBar()
	{
		final JMenuBar menuBar = new JMenuBar();
		this.setJMenuBar(menuBar);

		// 添加工具菜单
		final JMenu menu = new JMenu("工具");
		menuBar.add(menu);

		// JSON助手
		final JMenuItem jsonTool = new JMenuItem("JSON助手");
		menu.add(jsonTool);
		jsonTool.addActionListener(this::openJSONTool);

		// 图片工具
		final JMenuItem imageBase64Tool = new JMenuItem("Image转BASE64");
		menu.add(imageBase64Tool);
		imageBase64Tool.addActionListener(this::convertImageToBase64);

		final JMenuItem kafkaTool = new JMenuItem("Kafka助手");
		menu.add(kafkaTool);
		kafkaTool.addActionListener(this::openKafkaTools);

		// 密码助手
		final JMenuItem passwdTool = new JMenuItem("密码助手");
		menu.add(passwdTool);
		passwdTool.addActionListener(this::openPasswdTool);

		//PDF助手
		final JMenuItem pdfTool = new JMenuItem("PDF助手");
		menu.add(pdfTool);
		pdfTool.addActionListener(this::openPDFTool);
	}

	/**
	 * 生成操作按钮
	 * @return
	 */
	private JPanel createOptions()
	{
		JPanel row = new JPanel(new GridBagLayout());

		sltTable = new JCheckBox("仅对选择的表");
		GBC gbc = new GBC(0, 0).setWeight(0, 0);
		row.add(sltTable, gbc);

		JButton makeBean = new JButton("生成Bean");
		gbc = new GBC(20, 0).setWeight(0, 0);
		row.add(makeBean, gbc);

		JButton makeDocs = new JButton("生成文档");
		gbc = new GBC(40, 0).setWeight(0, 0);
		row.add(makeDocs, gbc);

		makeDocs.addActionListener(e -> exportDocs());

		makeBean.addActionListener(e -> makeBeanFiles());

		return row;
	}

	/**
	 * 生成弹出菜单
	 * @return
	 */
	private JPopupMenu createPopupMenu()
	{
		JPopupMenu menu = new JPopupMenu();
		JMenuItem item = new JMenuItem("生成SELECT");
		menu.add(item);

		item.addActionListener(e -> {
			int idx = content.getTableList().getSelectedIndex();
			if(idx >= 0)
			{
				GenResultDialog dlg = new GenResultDialog();
				dlg.setVisible(true);

				DBTable table = dbTables.get(idx);
				String text = SQLHandler.getHandler().select(table);
				dlg.setText(text);
			}
		});

		item = new JMenuItem("生成UPDATE");
		item.addActionListener(e -> {
			int idx = content.getTableList().getSelectedIndex();
			if(idx >= 0)
			{
				GenResultDialog dlg = new GenResultDialog();
				dlg.setVisible(true);

				DBTable table = dbTables.get(idx);
				String text = SQLHandler.getHandler().update(table);
				dlg.setText(text);
			}
		});
		menu.add(item);

		item = new JMenuItem("生成INSERT");
		item.addActionListener(e -> {
			int idx = content.getTableList().getSelectedIndex();
			if(idx >= 0)
			{
				GenResultDialog dlg = new GenResultDialog();
				dlg.setVisible(true);

				DBTable table = dbTables.get(idx);
				String text = SQLHandler.getHandler().insert(table);
				dlg.setText(text);
			}
		});
		menu.add(item);

		item = new JMenuItem("生成JavaBean");
		item.addActionListener(e->{
			int idx = content.getTableList().getSelectedIndex();
			if(idx >= 0)
			{
				GenResultDialog dlg = new GenResultDialog();
				dlg.setVisible(true);

				DBTable table = dbTables.get(idx);
				String text = BeanFileHandler.getHandler().makeBeanContent(table);
				dlg.setText(text);

			}
		});
		menu.add(item);

		item = new JMenuItem("MyBatis Generate");
		item.addActionListener(e->{
			int idx = content.getTableList().getSelectedIndex();
			if(idx >= 0)
			{
				DBTable table = dbTables.get(idx);
				MybatisGeneratorFrame dlg = new MybatisGeneratorFrame(connectionConfiguration, table.getName());
				dlg.setLocationRelativeTo(null);
				dlg.setVisible(true);
			}
		});
		menu.add(item);

		item = new JMenuItem("MyBatis Plus Generate");
		item.addActionListener(event->{
			int idx = content.getTableList().getSelectedIndex();
			if(idx >= 0)
			{
				DBTable table = dbTables.get(idx);
				MybatisPlusGeneratorFrame dlg = new MybatisPlusGeneratorFrame(dataSourceConfig, table.getName());
				dlg.setLocationRelativeTo(null);
				dlg.setVisible(true);
			}
		});
		menu.add(item);

		return menu;
	}

	@Override
	public void onConnect(String driver, String jdbcUrl, String user, String password)
	{
		connectionConfiguration = new JDBCConnectionConfiguration();
		connectionConfiguration.setConnectionURL(jdbcUrl);
		connectionConfiguration.setDriverClass(driver);
		connectionConfiguration.setUserId(user);
		connectionConfiguration.setPassword(password);

		dataSourceConfig = new DataSourceConfig.Builder(jdbcUrl, user, password)
				.build();

		logger.debug("driver: {}, url:{}, user: {}, pass: {}", driver, jdbcUrl, user, password);
		try
		{
			Class.forName(driver);
		}
		catch(ClassNotFoundException ex)
		{
			JOptionPane.showMessageDialog(this, "无法加载数据库驱动类: " + driver);
			return;
		}

		Connection conn = null;
		try
		{
			conn = DriverManager.getConnection(jdbcUrl, user, password);
			dbTables = DBUtils.getTables(conn);

			//更新界面
			DataTableListModel model = new DataTableListModel(dbTables);
			content.getTableList().setModel(model);

			logger.debug("数据库获取成功");
		}
		catch(SQLException ex)
		{
			JOptionPane.showMessageDialog(this, "数据库连接失败: " + ex.getMessage());
			return;
		}
		finally
		{
			DBUtils.close(conn);
		}
	}

	@Override
	public void valueChanged(ListSelectionEvent e)
	{
		if(e.getValueIsAdjusting())
		{
			return;
		}

		DBTable table = null;
		Object source = e.getSource();
		if(source instanceof JList)
		{
			@SuppressWarnings("unchecked")
			JList<String> list = (JList<String>)source;
			String name = list.getSelectedValue();
			for(DBTable tb : dbTables)
			{
				if(Objects.equals(name, tb.getName()))
				{
					table = tb;
					break;
				}
			}
		}

		if(table != null)
		{
			content.getDetailTable().setModel(new DataTableModel(table.getColumns()));
		}

		logger.debug("当前选择(table: {})", table.getName());
	}

	/**
	 * 生成java bean程序文件
	 */
	public void makeBeanFiles()
	{
		List<DBTable> tables = getSelectedTables();
		if(tables == null || tables.isEmpty())
		{
			JOptionPane.showMessageDialog(this, "没有需要导出的表!");
			return;
		}

		JFileChooser chooser = new JFileChooser();
		chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		if(JFileChooser.APPROVE_OPTION == chooser.showDialog(this, "选择"))
		{
			String dir = chooser.getSelectedFile().getPath();

			BeanFileHandler handler = BeanFileHandler.getHandler();
			handler.makeBeanFiles(tables, dir);

			logger.debug("bean文件导出成功: {}", dir);
			JOptionPane.showMessageDialog(this, "生成成功!");
		}
	}

	/**
	 * 导出数据库文档
	 */
	private void exportDocs()
	{
		List<DBTable> tables = getSelectedTables();
		if(tables == null || tables.isEmpty())
		{
			JOptionPane.showMessageDialog(this, "没有需要导出的表!");
			return;
		}

		JFileChooser chooser = new JFileChooser();
		chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		if(JFileChooser.APPROVE_OPTION == chooser.showDialog(this, "选择此处"))
		{
			String dir = chooser.getSelectedFile().getPath();

			//检测目录是否存在
			File dirFile = new File(dir);
			if(!dirFile.exists())
			{
				dirFile.mkdirs();
			}

			String docFile = dir + File.separatorChar + "数据库文档.md";
			DBDocHandler handler = DBDocHandler.getHandler();
			handler.exportDocs(tables, docFile);

			logger.debug("文档导出成功: {}", docFile);
			JOptionPane.showMessageDialog(this, docFile + "生成成功!");
		}
	}

	/**
	 * 获取当前选中的表
	 * @return
	 */
	private List<DBTable> getSelectedTables()
	{
		List<DBTable> tables = null;
		if(sltTable.isSelected())
		{
			int[] indexes = content.getTableList().getSelectedIndices();
			if(indexes != null && indexes.length > 0)
			{
				tables = new ArrayList<DBTable>();
				for(int i = 0; i < indexes.length; i++)
				{
					tables.add(dbTables.get(indexes[i]));
				}
			}
		}
		else
		{
			tables = dbTables;
		}

		return tables;
	}

	/**
	 * 将图片转换成Base64编码
	 * @param event
	 */
	private void convertImageToBase64(ActionEvent event)
	{
		ImageBase64Frame ibframe = new ImageBase64Frame();
		ibframe.setLocationRelativeTo(this);
		ibframe.setVisible(true);
	}

	/**
	 * Kafka助手
	 * @param event
	 */
	private void openKafkaTools(ActionEvent event)
	{
		KafkaToolsFrame frame = new KafkaToolsFrame();
		frame.setLocationRelativeTo(this);
		frame.setVisible(true);
	}

	/**
	 * 打开JSON助手
	 * @param event
	 */
	private void openJSONTool(ActionEvent event)
	{
		JSONToolFrame frame = new JSONToolFrame();
		frame.setLocationRelativeTo(this);
		frame.setVisible(true);
	}

	/**
	 * 打开密码助手
	 * @param event
	 */
	private void openPasswdTool(final ActionEvent event)
	{
		JFrame frame = new PasswordToolFrame();
		frame.setLocationRelativeTo(this);
		frame.setVisible(true);
	}

	/**
	 * 打开PDF助手工具
	 * @param event
	 */
	private void openPDFTool(final ActionEvent event)
	{
		final JFrame frame = new PDFToolsFrame();
		frame.setLocationRelativeTo(this);
		frame.setVisible(true);
	}
}
